Source code for hysop.backend.device.opencl.opencl_allocator
# Copyright (c) HySoP 2011-2024
#
# This file is part of HySoP software.
# See "https://particle_methods.gricad-pages.univ-grenoble-alpes.fr/hysop-doc/"
# for further info.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from abc import ABCMeta, abstractmethod
import numpy as np
from hysop.backend.device.opencl import cl, cl_api
from hysop.core.memory.allocator import AllocatorBase
from hysop.backend.device.opencl.opencl_buffer import OpenClBuffer
[docs]
class OpenClAllocator(AllocatorBase, metaclass=ABCMeta):
"""
Base class for OpenCl backend allocators.
"""
def __new__(cls, queue, mem_flags=cl.mem_flags.READ_WRITE, verbose=None):
return super().__new__(cls, verbose=verbose)
def __init__(self, queue, mem_flags=cl.mem_flags.READ_WRITE, verbose=None):
super().__init__(verbose=verbose)
if queue.device.type == cl.device_type.CPU:
# we assume zero copy capabilitiy for CPU devices
mem_flags |= cl.mem_flags.ALLOC_HOST_PTR
self._queue = queue
self._mem_flags = mem_flags
if mem_flags & cl.mem_flags.COPY_HOST_PTR:
raise ValueError(
"pyopencl.mem_flags.COPY_HOST_PTR cannot be passed for an allocator."
)
self._max_alloc_size = queue.device.max_mem_alloc_size
[docs]
def max_alloc_size(self):
"""Max allocatable size in bytes."""
return self._max_alloc_size
[docs]
def get_queue(self):
return self._queue
[docs]
def get_context(self):
return self._queue.context
[docs]
def get_device(self):
return self._queue.device
[docs]
def get_mem_flags(self):
return self._mem_flags
queue = property(get_queue)
context = property(get_context)
device = property(get_device)
mem_flags = property(get_mem_flags)
[docs]
def allocate(self, nbytes, **kwds):
"""
Wraps _allocate_impl to raise an MemoryError if a cl.Error with the
is_out_of_memory flag.
Should return an hysop.core.memory.buffer.OpenClBuffer
"""
super().allocate(nbytes=nbytes, **kwds)
try:
return self._allocate_impl(nbytes=nbytes)
except cl.Error as e:
raise MemoryError(str(e))
[docs]
def is_on_host(self):
"""
Return true if buffers are allocated in host memory.
"""
return self.device.type == cl.device_type.CPU
@abstractmethod
def _allocate_impl(nbytes):
pass
[docs]
def prefix(self):
return f"{self.full_tag}: "
[docs]
class OpenClDeferredAllocator(OpenClAllocator):
"""
Deferred OpenCL allocator, memory is allocated when used on device.
"""
is_deferred = True
def _allocate_impl(self, nbytes):
assert isinstance(nbytes, int)
return OpenClBuffer(context=self.context, mem_flags=self.mem_flags, size=nbytes)